Packages

pacman::p_load(dplyr, ggplot2, readr, haven, broom, purrr, tidyr, magrittr, labelled, sjPlot, viridis, forcats, ggthemes, cluster, factoextra, fpc)

Data

ches <- get(load("data/Rdata/ches_final.Rdata"))

Indeces

range01 <- function(x){(x - min(x, na.rm = T)) / (max(x, na.rm = T) - min(x, na.rm = T))}
ches <- ches %>% 
  mutate(populism = antielite_salience + corrupt_salience) %>% 
  mutate(populism2 = range01(range01(antielite_salience) + 
                               (1 - range01(eu_position)))*100) %>% #+ 
                           #    (1 - range01(eu_budgets)))*100) %>% 
  mutate(liberalism = sociallifestyle + civlib_laworder + galtan) %>% 
  mutate(populism = range01(populism)*100) %>% 
  mutate(liberalism = range01(liberalism)*100) #%>% 
  #filter(year > 2009)

Horse-shoe

ches %>% 
  ggplot(aes(liberalism, populism, colour = eu_position)) + 
  geom_point() +
  geom_smooth(method = "lm", formula = y ~ poly(x, 2))+
  #geom_text_repel(aes(liberalism, populism, label = party_cntry)) +
  ggthemes::theme_hc() +
  viridis::scale_color_viridis()

Clustering

set.seed(2018)
ches_cluster_data <- ches %>% 
  select(party_name, vote_id, liberalism, populism2) %>% 
  drop_na(liberalism, populism2) %>% 
  as.data.frame()
ches_cluster <- ches_cluster_data %>% 
  select(-party_name, -vote_id) %>% 
  purrr::map_df(scale) 
distance <- get_dist(ches_cluster)
fviz_dist(distance, 
 gradient = list(low = "#00AFBB", 
                 mid = "white",
                 high = "#FC4E07"))

kmeans() function returns a list of components, including:

  • cluster: A vector of integers (from 1:k) indicating the cluster to which each point is allocated
  • centers: A matrix of cluster centers (clustqer means)
  • totss: The total sum of squares (TSS), i.e (xi ≠ x ̄)2. TSS measures the total variance in the data.
  • withinss: Vector of within-cluster sum of squares, one component per cluster
  • tot.withinss: Total within-cluster sum of squares, i.e. sum(withinss)
  • betweenss: The between-cluster sum of squares, i.e. totss ≠ tot.withinss
  • size: The number of observations in each cluster
k3 <- kmeans(ches_cluster, centers = 3, nstart = 25, iter.max = 10)
ggf <- fviz_cluster(k3, data = ches_cluster, show.clust.cent = T, text = "vote_id")
ggf + theme_gdocs()

fviz_cluster(
  k3, 
  data = ches_cluster,
  palette = c("#2E9FDF", "#00AFBB", "#E7B800"), 
  ellipse.type = "euclid", # Concentration ellipse star.plot = TRUE, # Add segments from centroids to items repel = TRUE, # Avoid label overplotting (slow)
  ggtheme = theme_minimal()
)

# Elbow method
fviz_nbclust(ches_cluster, kmeans, method = "wss") +
  geom_vline(xintercept = 4, linetype = 2) +
  labs(subtitle = "Elbow method") + 
  theme_gdocs()

# Silhouette method
fviz_nbclust(ches_cluster, kmeans, method = "silhouette") +
  labs(subtitle = "Silhouette method") +
  theme_gdocs()

# Gap statistic
# nboot = 50 to keep the function speedy.
# recommended value: nboot= 500 for your analysis.
# Use verbose = FALSE to hide computing progression.
fviz_nbclust(ches_cluster, kmeans, nstart = 25, method = "gap_stat", nboot = 50) + 
  labs(subtitle = "Gap statistic method") +
  theme_gdocs()
Clustering k = 1,2,..., K.max (= 10): .. done
Bootstrapping, b = 1,2,..., B (= 50)  [one "." per sample]:
.................................................. 50 

According to these observations, it’s possible to define k = 4 as the optimal number of clusters in the data.

2 dimensions do not need pca

library(purrr)
res <- purrr::map(2:8, ~ kmeans(ches_cluster, .))
library(ggfortify)
autoplot(res, data = ches_cluster, ncol = 3) + theme(legend.position = "none")

normal scatterplots

k_cluster_dat <- 2:8 %>%
  purrr::map(~ kmeans(ches_cluster, .x)$cluster) %>%
  reduce(cbind) %>%
  as_tibble() %>%
  set_names(paste0("k", 2:8)) %>%
  cbind(ches_cluster, .)
k_cluster_dat %>%
  gather("k", "value", -liberalism, -populism2) %>%
  ggplot(aes(liberalism, populism2, colour = as.factor(value))) +
  geom_point() +
  facet_wrap(~k) +
  scale_colour_viridis(discrete = T, direction = -1) + 
  theme_hc() +
  theme(legend.position = "none")

cbind(ches_cluster, cluster = k3$cluster) %>%
  group_by(cluster) %>%
  summarise_all(.funs = list(m = mean, s = sd))

K-Medoids

The most common k-medoids clustering methods is the PAM algorithm (Partitioning Around Medoids, Kaufman & Rousseeuw, 1990).

res_pam <- pam(ches_cluster, 3, metric = "euclidean", stand = FALSE)
res_pam$clustering
  [1] 1 1 1 1 2 2 2 2 2 1 3 1 3 2 1 2 1 2 1 3 1 1 2 2 2 1 1 2 3 3 1 1 2 2 1 3 3
 [38] 3 1 1 3 1 2 1 2 2 2 1 1 2 1 1 1 1 1 1 1 1 1 2 3 3 2 2 2 2 1 1 2 2 2 1 1 1
 [75] 1 1 3 2 3 2 1 1 2 3 3 2 2 2 2 1 2 1 1 3 1 2 3 1 1 2 1 1 1 1 1 3 1 2 2 2 1
[112] 3 2 2 3 1 1 3 3 1 2 2 1 3 1 1 2 1 1 1 2 2 2 1 3 1 1 2 2 2 3 3 2 2 1 3 3 2
[149] 2 2 3 2 1 2 1 3 3 2 2 2 1 1 1 2 3 3 1 1 1 3 2 2 3 2 3 3 2 2 2 3 3 2 1 3 1
[186] 2 3 2 1 3 3 3 2 2 2 2 2 2 3 2 2 2 2 2 2 3 1 2 3 3 2 2 1 2 2 2 2 1 1 1 2 1
[223] 2 1 1 1 3 3 1 3 1 3 1 3 1 2 3 2 1 3 3 1 1 3 1 2 2 1 1 2 3 3 2 2 1 2 2 1 1
[260] 1 3 1 2 2 1 2 1 1
fviz_nbclust(ches_cluster, pam, method = "silhouette")+
theme_hc()

km_cluster_dat <- 2:8 %>%
  purrr::map(~ pam(ches_cluster, k = ., metric = "euclidean", stand = FALSE)$clustering) %>%
  reduce(cbind) %>%
  as_tibble() %>%
  set_names(paste0("k", 2:8)) %>%
  cbind(ches_cluster, .)
gg_km <- km_cluster_dat %>%
  gather("k", "value", -liberalism, -populism2) %>%
  ggplot(aes(liberalism, populism2, colour = as.factor(value))) +
  geom_point() +
  facet_wrap(~k) +
  scale_colour_viridis(discrete = T, direction = -1) + 
  theme_hc() +
  theme(legend.position = "none")
gg_km

res_pam$medoids
     liberalism  populism2
[1,] -0.9858867 -0.2065320
[2,]  0.2614908 -0.7920694
[3,]  1.3112089  1.2857607
cbind(ches_cluster, cluster = res_pam$clustering) %>%
  group_by(cluster) %>%
  summarise_all(.funs = list(m = median))
fviz_nbclust(ches_cluster, clara, method = "silhouette")+
theme_classic()

HCA

res.dist <- dist(ches_cluster, method = "euclidean")
res.hc <- hclust(d = res.dist, method = "ward.D2")
fviz_dend(res.hc, cex = 0.5)

# Cut tree into 3 groups
grp <- cutree(res.hc, k = 3)
fviz_dend(
  res.hc, 
  k = 3, # Cut in four groups
  cex = 0.5, # label size
  k_colors = c("#2E9FDF", "#00AFBB", "#E7B800"),
  color_labels_by_k = TRUE, # color labels by groups
  rect = TRUE # Add rectangle around groups
)

fviz_dend(
  res.hc, 
  cex = 1, 
  k = 3,
  k_colors = "jco", 
  type = "circular"
)
require("igraph")
Lade nötiges Paket: igraph

Attache Paket: ‘igraph’

The following object is masked from ‘package:clValid’:

    clusters

The following object is masked from ‘package:tidyr’:

    crossing

The following objects are masked from ‘package:purrr’:

    compose, simplify

The following objects are masked from ‘package:dplyr’:

    as_data_frame, groups, union

The following objects are masked from ‘package:stats’:

    decompose, spectrum

The following object is masked from ‘package:base’:

    union
ggrep <- fviz_dend(res.hc, k = 3, k_colors = "jco",
          type = "phylogenic", repel = TRUE)
ggrep

fviz_dend(res.hc, k = 3, # Cut in four groups
          k_colors = "jco",
          type = "phylogenic", 
          repel = TRUE,
          phylo_layout = "layout_with_drl")

fviz_dend(res.hc, k = 3, # Cut in four groups
          k_colors = "jco",
          type = "phylogenic", 
          repel = TRUE,
          phylo_layout = "layout_as_tree")

fviz_dend(res.hc, k = 3, # Cut in four groups
          k_colors = "jco",
          type = "phylogenic", 
          repel = TRUE,
          phylo_layout = "layout.gem")

fviz_dend(res.hc, k = 3, # Cut in four groups
          k_colors = "jco",
          type = "phylogenic", 
          repel = TRUE,
          phylo_layout = "layout.mds")

gg10 <- fviz_dend(res.hc, k = 3, # Cut in four groups
          k_colors = "jco",
          type = "phylogenic", 
          repel = TRUE,
          phylo_layout = "layout_with_lgl")
gg10

Compare clustering algorithms in R

library(clValid)
# Iris data set:
# - Remove Species column and scale df <- scale(iris[, -5])
# Compute clValid
clmethods <- c("hierarchical","kmeans","pam") 
intern <- clValid(
  ches_cluster %>% as.matrix, 
  nClust = 2:8,
  clMethods = clmethods, 
  validation = "internal"
) 
rownames for data not specified, using 1:nrow(data)
summary(intern)

Clustering Methods:
 hierarchical kmeans pam 

Cluster sizes:
 2 3 4 5 6 7 8 

Validation Measures:
                                 2       3       4       5       6       7       8
                                                                                  
hierarchical Connectivity  10.2683 17.5187 24.7937 35.0802 42.4873 45.0024 54.0444
             Dunn           0.0489  0.0569  0.0586  0.0678  0.0830  0.0886  0.0939
             Silhouette     0.4421  0.3938  0.4172  0.3977  0.3853  0.3710  0.3428
kmeans       Connectivity  27.6107 28.8794 42.6972 48.6603 59.4067 59.1024 80.4679
             Dunn           0.0336  0.0253  0.0327  0.0478  0.0201  0.0357  0.0419
             Silhouette     0.4495  0.4394  0.4634  0.4296  0.3995  0.4060  0.3596
pam          Connectivity  26.5952 39.1357 39.8861 38.1683 67.1135 73.0849 78.7849
             Dunn           0.0357  0.0331  0.0306  0.0334  0.0264  0.0243  0.0254
             Silhouette     0.4486  0.4179  0.4614  0.4267  0.4014  0.4006  0.3771

Optimal Scores:

             Score   Method       Clusters
Connectivity 10.2683 hierarchical 2       
Dunn          0.0939 hierarchical 8       
Silhouette    0.4634 kmeans       4       
# Stability measures
clmethods <- c("hierarchical","kmeans","pam")
stab <- clValid(
  ches_cluster %>% as.matrix,
  nClust = 2:6, 
  clMethods = clmethods,
  validation = "stability"
) # Display only optimal Scores
optimalScores(stab)

Model-Based Clustering

The model parameters can be estimated using the Expectation-Maximization (EM) algorithm initialized by hierarchical model-based clustering. Each cluster k is centered at the means μk, with increased density for points near the mean.

library(mclust)
mc <- Mclust(ches_cluster) # Model-based-clustering 
fitting ...

  |                                                                            
  |                                                                      |   0%
  |                                                                            
  |=                                                                     |   1%
  |                                                                            
  |=                                                                     |   2%
  |                                                                            
  |==                                                                    |   2%
  |                                                                            
  |==                                                                    |   3%
  |                                                                            
  |===                                                                   |   4%
  |                                                                            
  |===                                                                   |   5%
  |                                                                            
  |====                                                                  |   6%
  |                                                                            
  |=====                                                                 |   7%
  |                                                                            
  |======                                                                |   8%
  |                                                                            
  |======                                                                |   9%
  |                                                                            
  |=======                                                               |   9%
  |                                                                            
  |=======                                                               |  10%
  |                                                                            
  |========                                                              |  11%
  |                                                                            
  |========                                                              |  12%
  |                                                                            
  |=========                                                             |  13%
  |                                                                            
  |==========                                                            |  14%
  |                                                                            
  |==========                                                            |  15%
  |                                                                            
  |===========                                                           |  16%
  |                                                                            
  |============                                                          |  17%
  |                                                                            
  |=============                                                         |  18%
  |                                                                            
  |=============                                                         |  19%
  |                                                                            
  |==============                                                        |  20%
  |                                                                            
  |===============                                                       |  21%
  |                                                                            
  |===============                                                       |  22%
  |                                                                            
  |================                                                      |  23%
  |                                                                            
  |=================                                                     |  24%
  |                                                                            
  |==================                                                    |  25%
  |                                                                            
  |==================                                                    |  26%
  |                                                                            
  |===================                                                   |  27%
  |                                                                            
  |===================                                                   |  28%
  |                                                                            
  |====================                                                  |  28%
  |                                                                            
  |====================                                                  |  29%
  |                                                                            
  |=====================                                                 |  30%
  |                                                                            
  |=====================                                                 |  31%
  |                                                                            
  |======================                                                |  31%
  |                                                                            
  |=======================                                               |  32%
  |                                                                            
  |=======================                                               |  33%
  |                                                                            
  |========================                                              |  34%
  |                                                                            
  |========================                                              |  35%
  |                                                                            
  |=========================                                             |  35%
  |                                                                            
  |=========================                                             |  36%
  |                                                                            
  |==========================                                            |  37%
  |                                                                            
  |==========================                                            |  38%
  |                                                                            
  |===========================                                           |  39%
  |                                                                            
  |============================                                          |  39%
  |                                                                            
  |============================                                          |  40%
  |                                                                            
  |=============================                                         |  41%
  |                                                                            
  |=============================                                         |  42%
  |                                                                            
  |==============================                                        |  43%
  |                                                                            
  |===============================                                       |  44%
  |                                                                            
  |===============================                                       |  45%
  |                                                                            
  |================================                                      |  46%
  |                                                                            
  |=================================                                     |  46%
  |                                                                            
  |=================================                                     |  47%
  |                                                                            
  |==================================                                    |  48%
  |                                                                            
  |==================================                                    |  49%
  |                                                                            
  |===================================                                   |  50%
  |                                                                            
  |====================================                                  |  51%
  |                                                                            
  |====================================                                  |  52%
  |                                                                            
  |=====================================                                 |  53%
  |                                                                            
  |=====================================                                 |  54%
  |                                                                            
  |======================================                                |  54%
  |                                                                            
  |=======================================                               |  55%
  |                                                                            
  |=======================================                               |  56%
  |                                                                            
  |========================================                              |  57%
  |                                                                            
  |=========================================                             |  58%
  |                                                                            
  |=========================================                             |  59%
  |                                                                            
  |==========================================                            |  60%
  |                                                                            
  |==========================================                            |  61%
  |                                                                            
  |===========================================                           |  61%
  |                                                                            
  |============================================                          |  62%
  |                                                                            
  |============================================                          |  63%
  |                                                                            
  |=============================================                         |  64%
  |                                                                            
  |=============================================                         |  65%
  |                                                                            
  |==============================================                        |  65%
  |                                                                            
  |==============================================                        |  66%
  |                                                                            
  |===============================================                       |  67%
  |                                                                            
  |===============================================                       |  68%
  |                                                                            
  |================================================                      |  69%
  |                                                                            
  |=================================================                     |  69%
  |                                                                            
  |=================================================                     |  70%
  |                                                                            
  |==================================================                    |  71%
  |                                                                            
  |==================================================                    |  72%
  |                                                                            
  |===================================================                   |  72%
  |                                                                            
  |===================================================                   |  73%
  |                                                                            
  |====================================================                  |  74%
  |                                                                            
  |====================================================                  |  75%
  |                                                                            
  |=====================================================                 |  76%
  |                                                                            
  |======================================================                |  77%
  |                                                                            
  |=======================================================               |  78%
  |                                                                            
  |=======================================================               |  79%
  |                                                                            
  |========================================================              |  80%
  |                                                                            
  |=========================================================             |  81%
  |                                                                            
  |=========================================================             |  82%
  |                                                                            
  |==========================================================            |  83%
  |                                                                            
  |===========================================================           |  84%
  |                                                                            
  |============================================================          |  85%
  |                                                                            
  |============================================================          |  86%
  |                                                                            
  |=============================================================         |  87%
  |                                                                            
  |==============================================================        |  88%
  |                                                                            
  |==============================================================        |  89%
  |                                                                            
  |===============================================================       |  90%
  |                                                                            
  |===============================================================       |  91%
  |                                                                            
  |================================================================      |  91%
  |                                                                            
  |================================================================      |  92%
  |                                                                            
  |=================================================================     |  93%
  |                                                                            
  |==================================================================    |  94%
  |                                                                            
  |===================================================================   |  95%
  |                                                                            
  |===================================================================   |  96%
  |                                                                            
  |====================================================================  |  97%
  |                                                                            
  |====================================================================  |  98%
  |                                                                            
  |===================================================================== |  98%
  |                                                                            
  |===================================================================== |  99%
  |                                                                            
  |======================================================================| 100%
summary(mc)
----------------------------------------------------
Gaussian finite mixture model fitted by EM algorithm 
----------------------------------------------------

Mclust EII (spherical, equal volume) model with 4 components:

 log.likelihood   n df       BIC       ICL
      -655.0623 268 12 -1377.216 -1431.308

Clustering table:
 1  2  3  4 
91 88 53 36 
# BIC values used for choosing the number of clusters 
fviz_mclust(mc, "BIC", palette = "jco")

# Classification: plot showing the clustering 
fviz_mclust(mc, "classification", geom = "point",
pointsize = 1.5, palette = "jco") # Classification uncertainty

fviz_mclust(mc, "uncertainty", palette = "jco")

ches %>% 
  ggplot(aes(liberalism, populism, colour = mc$classification)) + 
  geom_point() +
  #geom_smooth(method = "lm", formula = y ~ poly(x, 2))+
  #geom_text_repel(aes(liberalism, populism, label = party_cntry)) +
  ggthemes::theme_hc() +
  viridis::scale_color_viridis() + 
  geom_density2d(alpha = .7, color = "gray") # Add 2D density 

library(highcharter)

df1 <- tibble(vote = paste(ches_cluster_data$party_name, ches_cluster_data$vote_id, sep = " "), cluster = k3$cluster, x = as.vector(ches_cluster$liberalism), y = as.vector(ches_cluster$populism2)) %>%
  filter(stringr::str_detect(vote, "DE_"))
hchart(df1, hcaes(x = x, y = y, name = vote, color = cluster), type = 'scatter') %>%
  hc_add_theme(hc_theme_smpl()) %>%
  hc_tooltip(
    formatter = JS("function(){
                    return ('Party: <strong>' + this.point.vote + '</strong><br> X: ' + this.x + ' <br> Y: ' + this.y + ' <br>')
                  }")) %>%
  hc_chart(zoomType = "xy")

World Map

ggmap
Warnung in gzfile(file, "wb")
  kann komprimierte Datei '/Users/simonroth/Dropbox/projects/pol_efficacy/.Rproj.user/shared/notebooks/CDBFB3FD-A2_ches_clustering/1/473BEA9DF7ECD836/c78nbmwozwwyp_t/524d23442b1d4dbeae748ccb41943d92.snapshot' nicht öffnen. Grund evtl. 'No such file or directory'
Fehler in gzfile(file, "wb") : kann Verbindung nicht öffnen
Fehler in (function (which = dev.cur())  : 
  QuartzBitmap_Output - unable to open file '/Users/simonroth/Dropbox/projects/pol_efficacy/.Rproj.user/shared/notebooks/CDBFB3FD-A2_ches_clustering/1/473BEA9DF7ECD836/c78nbmwozwwyp_t/_rs_chunk_plot_001.png'
#ess_clean <- ess_sub  %>% 
  # mutate(eu_member =
  #          recode_factor(cntry,
  #               DE = 1958, BE = 1958, FR = 1958, NL = 1958, IE = 1973,
  #               GB = 1973, FI = 1995, AT = 1995, SE = 1995, EE = 2004,
  #               PL = 2004, SI = 2004, CZ = 2004, CH = 0, IL = 0,
  #               IS = 0, NO = 0, RU = 0
  #             )
  #       ) %>%
  # mutate(post_com = ifelse(region %in% c("Estonia", "Poland", "Slovenia", "Czech Republic", "Russian Federation"), "Post C", "West"))

Get Info

  • horse shoe theory
  • Set up Rmarkdown paper template
  • Set up Project page
p5 <- step5 %>%
  select(gndr, edu, income, rel, year) %>%
  gather("var", "value") %>%
  ggplot(aes(value, fill = var)) +
  geom_bar() +
  facet_wrap(~var, scales = "free") +
  viridis::scale_fill_viridis(discrete = T)
p5
LS0tCnRpdGxlOiAiQ0hFUyBDbHVzdGVyaW5nIgpzdWJ0aXRsZTogIkNsc3V0ZXJpbmcgYW5kIEZhY3RvciBTY29yZXMiCmF1dGhvcjogIlJlYmVjY2EgJiBTaW1vbiAiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCiMjIFBhY2thZ2VzCgpgYGB7cn0KcGFjbWFuOjpwX2xvYWQoZHBseXIsIGdncGxvdDIsIHJlYWRyLCBoYXZlbiwgYnJvb20sIHB1cnJyLCB0aWR5ciwgbWFncml0dHIsIGxhYmVsbGVkLCBzalBsb3QsIHZpcmlkaXMsIGZvcmNhdHMsIGdndGhlbWVzLCBjbHVzdGVyLCBmYWN0b2V4dHJhLCBmcGMpCmBgYAoKIyMgRGF0YQoKYGBge3J9CmNoZXMgPC0gZ2V0KGxvYWQoImRhdGEvUmRhdGEvY2hlc19maW5hbC5SZGF0YSIpKQpgYGAKCgojIyBJbmRlY2VzIAoKYGBge3J9CnJhbmdlMDEgPC0gZnVuY3Rpb24oeCl7KHggLSBtaW4oeCwgbmEucm0gPSBUKSkgLyAobWF4KHgsIG5hLnJtID0gVCkgLSBtaW4oeCwgbmEucm0gPSBUKSl9CmNoZXMgPC0gY2hlcyAlPiUgCiAgbXV0YXRlKHBvcHVsaXNtID0gYW50aWVsaXRlX3NhbGllbmNlICsgY29ycnVwdF9zYWxpZW5jZSkgJT4lIAogIG11dGF0ZShwb3B1bGlzbTIgPSByYW5nZTAxKHJhbmdlMDEoYW50aWVsaXRlX3NhbGllbmNlKSArIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKDEgLSByYW5nZTAxKGV1X3Bvc2l0aW9uKSkpKjEwMCkgJT4lICMrIAogICAgICAgICAgICAgICAgICAgICAgICAgICAjICAgICgxIC0gcmFuZ2UwMShldV9idWRnZXRzKSkpKjEwMCkgJT4lIAogIG11dGF0ZShsaWJlcmFsaXNtID0gc29jaWFsbGlmZXN0eWxlICsgY2l2bGliX2xhd29yZGVyICsgZ2FsdGFuKSAlPiUgCiAgbXV0YXRlKHBvcHVsaXNtID0gcmFuZ2UwMShwb3B1bGlzbSkqMTAwKSAlPiUgCiAgbXV0YXRlKGxpYmVyYWxpc20gPSByYW5nZTAxKGxpYmVyYWxpc20pKjEwMCkgIyU+JSAKICAjZmlsdGVyKHllYXIgPiAyMDA5KQpgYGAKCiMgSG9yc2Utc2hvZQoKYGBge3J9CmNoZXMgJT4lIAogIGdncGxvdChhZXMobGliZXJhbGlzbSwgcG9wdWxpc20sIGNvbG91ciA9IGV1X3Bvc2l0aW9uKSkgKyAKICBnZW9tX3BvaW50KCkgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIGZvcm11bGEgPSB5IH4gcG9seSh4LCAyKSkrCiAgI2dlb21fdGV4dF9yZXBlbChhZXMobGliZXJhbGlzbSwgcG9wdWxpc20sIGxhYmVsID0gcGFydHlfY250cnkpKSArCiAgZ2d0aGVtZXM6OnRoZW1lX2hjKCkgKwogIHZpcmlkaXM6OnNjYWxlX2NvbG9yX3ZpcmlkaXMoKQpgYGAKCgoKIyMgQ2x1c3RlcmluZwoKYGBge3J9CnNldC5zZWVkKDIwMTgpCmNoZXNfY2x1c3Rlcl9kYXRhIDwtIGNoZXMgJT4lIAogIHNlbGVjdChwYXJ0eV9uYW1lLCB2b3RlX2lkLCBsaWJlcmFsaXNtLCBwb3B1bGlzbTIpICU+JSAKICBkcm9wX25hKGxpYmVyYWxpc20sIHBvcHVsaXNtMikgJT4lIAogIGFzLmRhdGEuZnJhbWUoKQoKY2hlc19jbHVzdGVyIDwtIGNoZXNfY2x1c3Rlcl9kYXRhICU+JSAKICBzZWxlY3QoLXBhcnR5X25hbWUsIC12b3RlX2lkKSAlPiUgCiAgcHVycnI6Om1hcF9kZihzY2FsZSkgCmBgYAoKYGBge3J9CmRpc3RhbmNlIDwtIGdldF9kaXN0KGNoZXNfY2x1c3RlcikKZnZpel9kaXN0KGRpc3RhbmNlLCAKIGdyYWRpZW50ID0gbGlzdChsb3cgPSAiIzAwQUZCQiIsIAogICAgICAgICAgICAgICAgIG1pZCA9ICJ3aGl0ZSIsCiAgICAgICAgICAgICAgICAgaGlnaCA9ICIjRkM0RTA3IikpCmBgYAoKYGttZWFucygpYCBmdW5jdGlvbiByZXR1cm5zIGEgbGlzdCBvZiBjb21wb25lbnRzLCBpbmNsdWRpbmc6CgoqIGBjbHVzdGVyYDogQSB2ZWN0b3Igb2YgaW50ZWdlcnMgKGZyb20gMTprKSBpbmRpY2F0aW5nIHRoZSBjbHVzdGVyIHRvIHdoaWNoIGVhY2ggcG9pbnQgaXMgYWxsb2NhdGVkCiogYGNlbnRlcnNgOiBBIG1hdHJpeCBvZiBjbHVzdGVyIGNlbnRlcnMgKGNsdXN0cWVyIG1lYW5zKQoqIGB0b3Rzc2A6IFRoZSB0b3RhbCBzdW0gb2Ygc3F1YXJlcyAoVFNTKSwgaS5lICh4aSDiiaAgeCDMhCkyLiBUU1MgbWVhc3VyZXMgdGhlIHRvdGFsIHZhcmlhbmNlIGluIHRoZSBkYXRhLgoqIGB3aXRoaW5zc2A6IFZlY3RvciBvZiB3aXRoaW4tY2x1c3RlciBzdW0gb2Ygc3F1YXJlcywgb25lIGNvbXBvbmVudCBwZXIgY2x1c3RlcgoqIGB0b3Qud2l0aGluc3NgOiBUb3RhbCB3aXRoaW4tY2x1c3RlciBzdW0gb2Ygc3F1YXJlcywgaS5lLiBzdW0od2l0aGluc3MpCiogYGJldHdlZW5zc2A6IFRoZSBiZXR3ZWVuLWNsdXN0ZXIgc3VtIG9mIHNxdWFyZXMsIGkuZS4gdG90c3Mg4omgIHRvdC53aXRoaW5zcwoqIGBzaXplYDogVGhlIG51bWJlciBvZiBvYnNlcnZhdGlvbnMgaW4gZWFjaCBjbHVzdGVyCgpgYGB7cn0KazMgPC0ga21lYW5zKGNoZXNfY2x1c3RlciwgY2VudGVycyA9IDMsIG5zdGFydCA9IDI1LCBpdGVyLm1heCA9IDEwKQpnZ2YgPC0gZnZpel9jbHVzdGVyKGszLCBkYXRhID0gY2hlc19jbHVzdGVyLCBzaG93LmNsdXN0LmNlbnQgPSBULCB0ZXh0ID0gInZvdGVfaWQiKQpnZ2YgKyB0aGVtZV9nZG9jcygpCmBgYAoKCmBgYHtyfQpmdml6X2NsdXN0ZXIoCiAgazMsIAogIGRhdGEgPSBjaGVzX2NsdXN0ZXIsCiAgcGFsZXR0ZSA9IGMoIiMyRTlGREYiLCAiIzAwQUZCQiIsICIjRTdCODAwIiksIAogIGVsbGlwc2UudHlwZSA9ICJldWNsaWQiLCAjIENvbmNlbnRyYXRpb24gZWxsaXBzZSBzdGFyLnBsb3QgPSBUUlVFLCAjIEFkZCBzZWdtZW50cyBmcm9tIGNlbnRyb2lkcyB0byBpdGVtcyByZXBlbCA9IFRSVUUsICMgQXZvaWQgbGFiZWwgb3ZlcnBsb3R0aW5nIChzbG93KQogIGdndGhlbWUgPSB0aGVtZV9taW5pbWFsKCkKKQpgYGAKCgoKYGBge3J9CiMgRWxib3cgbWV0aG9kCmZ2aXpfbmJjbHVzdChjaGVzX2NsdXN0ZXIsIGttZWFucywgbWV0aG9kID0gIndzcyIpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSA0LCBsaW5ldHlwZSA9IDIpICsKICBsYWJzKHN1YnRpdGxlID0gIkVsYm93IG1ldGhvZCIpICsgCiAgdGhlbWVfZ2RvY3MoKQoKCiMgU2lsaG91ZXR0ZSBtZXRob2QKZnZpel9uYmNsdXN0KGNoZXNfY2x1c3Rlciwga21lYW5zLCBtZXRob2QgPSAic2lsaG91ZXR0ZSIpICsKICBsYWJzKHN1YnRpdGxlID0gIlNpbGhvdWV0dGUgbWV0aG9kIikgKwogIHRoZW1lX2dkb2NzKCkKCiMgR2FwIHN0YXRpc3RpYwojIG5ib290ID0gNTAgdG8ga2VlcCB0aGUgZnVuY3Rpb24gc3BlZWR5LgojIHJlY29tbWVuZGVkIHZhbHVlOiBuYm9vdD0gNTAwIGZvciB5b3VyIGFuYWx5c2lzLgojIFVzZSB2ZXJib3NlID0gRkFMU0UgdG8gaGlkZSBjb21wdXRpbmcgcHJvZ3Jlc3Npb24uCmZ2aXpfbmJjbHVzdChjaGVzX2NsdXN0ZXIsIGttZWFucywgbnN0YXJ0ID0gMjUsIG1ldGhvZCA9ICJnYXBfc3RhdCIsIG5ib290ID0gNTApICsgCiAgbGFicyhzdWJ0aXRsZSA9ICJHYXAgc3RhdGlzdGljIG1ldGhvZCIpICsKICB0aGVtZV9nZG9jcygpCmBgYAoKQWNjb3JkaW5nIHRvIHRoZXNlIG9ic2VydmF0aW9ucywgaXTigJlzIHBvc3NpYmxlIHRvIGRlZmluZSBrID0gNCBhcyB0aGUgb3B0aW1hbCBudW1iZXIgb2YgY2x1c3RlcnMgaW4gdGhlIGRhdGEuCgoKMiBkaW1lbnNpb25zIGRvIG5vdCBuZWVkIHBjYQoKYGBge3IsIGV2YWwgPSBGfQpsaWJyYXJ5KHB1cnJyKQpyZXMgPC0gcHVycnI6Om1hcCgyOjgsIH4ga21lYW5zKGNoZXNfY2x1c3RlciwgLikpCmxpYnJhcnkoZ2dmb3J0aWZ5KQphdXRvcGxvdChyZXMsIGRhdGEgPSBjaGVzX2NsdXN0ZXIsIG5jb2wgPSAzKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKYGBgCgpub3JtYWwgc2NhdHRlcnBsb3RzCgpgYGB7cn0Ka19jbHVzdGVyX2RhdCA8LSAyOjggJT4lCiAgcHVycnI6Om1hcCh+IGttZWFucyhjaGVzX2NsdXN0ZXIsIC54KSRjbHVzdGVyKSAlPiUKICByZWR1Y2UoY2JpbmQpICU+JQogIGFzX3RpYmJsZSgpICU+JQogIHNldF9uYW1lcyhwYXN0ZTAoImsiLCAyOjgpKSAlPiUKICBjYmluZChjaGVzX2NsdXN0ZXIsIC4pCgprX2NsdXN0ZXJfZGF0ICU+JQogIGdhdGhlcigiayIsICJ2YWx1ZSIsIC1saWJlcmFsaXNtLCAtcG9wdWxpc20yKSAlPiUKICBnZ3Bsb3QoYWVzKGxpYmVyYWxpc20sIHBvcHVsaXNtMiwgY29sb3VyID0gYXMuZmFjdG9yKHZhbHVlKSkpICsKICBnZW9tX3BvaW50KCkgKwogIGZhY2V0X3dyYXAofmspICsKICBzY2FsZV9jb2xvdXJfdmlyaWRpcyhkaXNjcmV0ZSA9IFQsIGRpcmVjdGlvbiA9IC0xKSArIAogIHRoZW1lX2hjKCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKYGBgCgoKCmBgYHtyfQpjYmluZChjaGVzX2NsdXN0ZXIsIGNsdXN0ZXIgPSBrMyRjbHVzdGVyKSAlPiUKICBncm91cF9ieShjbHVzdGVyKSAlPiUKICBzdW1tYXJpc2VfYWxsKC5mdW5zID0gbGlzdChtID0gbWVhbiwgcyA9IHNkKSkKYGBgCgoKIyMgSy1NZWRvaWRzCgpUaGUgbW9zdCBjb21tb24gay1tZWRvaWRzIGNsdXN0ZXJpbmcgbWV0aG9kcyBpcyB0aGUgUEFNIGFsZ29yaXRobSAoUGFydGl0aW9uaW5nIEFyb3VuZCBNZWRvaWRzLCBLYXVmbWFuICYgUm91c3NlZXV3LCAxOTkwKS4KCmBgYHtyfQpyZXNfcGFtIDwtIHBhbShjaGVzX2NsdXN0ZXIsIDMsIG1ldHJpYyA9ICJldWNsaWRlYW4iLCBzdGFuZCA9IEZBTFNFKQpyZXNfcGFtJGNsdXN0ZXJpbmcKCmZ2aXpfbmJjbHVzdChjaGVzX2NsdXN0ZXIsIHBhbSwgbWV0aG9kID0gInNpbGhvdWV0dGUiKSsKdGhlbWVfaGMoKQpgYGAKCmBgYHtyfQprbV9jbHVzdGVyX2RhdCA8LSAyOjggJT4lCiAgcHVycnI6Om1hcCh+IHBhbShjaGVzX2NsdXN0ZXIsIGsgPSAuLCBtZXRyaWMgPSAiZXVjbGlkZWFuIiwgc3RhbmQgPSBGQUxTRSkkY2x1c3RlcmluZykgJT4lCiAgcmVkdWNlKGNiaW5kKSAlPiUKICBhc190aWJibGUoKSAlPiUKICBzZXRfbmFtZXMocGFzdGUwKCJrIiwgMjo4KSkgJT4lCiAgY2JpbmQoY2hlc19jbHVzdGVyLCAuKQoKZ2dfa20gPC0ga21fY2x1c3Rlcl9kYXQgJT4lCiAgZ2F0aGVyKCJrIiwgInZhbHVlIiwgLWxpYmVyYWxpc20sIC1wb3B1bGlzbTIpICU+JQogIGdncGxvdChhZXMobGliZXJhbGlzbSwgcG9wdWxpc20yLCBjb2xvdXIgPSBhcy5mYWN0b3IodmFsdWUpKSkgKwogIGdlb21fcG9pbnQoKSArCiAgZmFjZXRfd3JhcCh+aykgKwogIHNjYWxlX2NvbG91cl92aXJpZGlzKGRpc2NyZXRlID0gVCwgZGlyZWN0aW9uID0gLTEpICsgCiAgdGhlbWVfaGMoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQpnZ19rbQpgYGAKCmBgYHtyfQpyZXNfcGFtJG1lZG9pZHMKYGBgCgpgYGB7cn0KY2JpbmQoY2hlc19jbHVzdGVyLCBjbHVzdGVyID0gcmVzX3BhbSRjbHVzdGVyaW5nKSAlPiUKICBncm91cF9ieShjbHVzdGVyKSAlPiUKICBzdW1tYXJpc2VfYWxsKC5mdW5zID0gbGlzdChtID0gbWVkaWFuKSkKYGBgCgpgYGB7cn0KZnZpel9uYmNsdXN0KGNoZXNfY2x1c3RlciwgY2xhcmEsIG1ldGhvZCA9ICJzaWxob3VldHRlIikrCnRoZW1lX2NsYXNzaWMoKQpgYGAKCiMgSENBCgpgYGB7cn0KcmVzLmRpc3QgPC0gZGlzdChjaGVzX2NsdXN0ZXIsIG1ldGhvZCA9ICJldWNsaWRlYW4iKQpyZXMuaGMgPC0gaGNsdXN0KGQgPSByZXMuZGlzdCwgbWV0aG9kID0gIndhcmQuRDIiKQpmdml6X2RlbmQocmVzLmhjLCBjZXggPSAwLjUpCmBgYAoKYGBge3J9CiMgQ3V0IHRyZWUgaW50byAzIGdyb3VwcwpncnAgPC0gY3V0cmVlKHJlcy5oYywgayA9IDMpCgpmdml6X2RlbmQoCiAgcmVzLmhjLCAKICBrID0gMywgIyBDdXQgaW4gZm91ciBncm91cHMKICBjZXggPSAwLjUsICMgbGFiZWwgc2l6ZQogIGtfY29sb3JzID0gYygiIzJFOUZERiIsICIjMDBBRkJCIiwgIiNFN0I4MDAiKSwKICBjb2xvcl9sYWJlbHNfYnlfayA9IFRSVUUsICMgY29sb3IgbGFiZWxzIGJ5IGdyb3VwcwogIHJlY3QgPSBUUlVFICMgQWRkIHJlY3RhbmdsZSBhcm91bmQgZ3JvdXBzCikKYGBgCgpgYGB7ciwgZmlnLmhlaWdodD0xMCwgZmlnLndpZHRoPTEwfQpmdml6X2RlbmQoCiAgcmVzLmhjLCAKICBjZXggPSAxLCAKICBrID0gMywKICBrX2NvbG9ycyA9ICJqY28iLCAKICB0eXBlID0gImNpcmN1bGFyIgopCmBgYAoKYGBge3J9CnJlcXVpcmUoImlncmFwaCIpCmdncmVwIDwtIGZ2aXpfZGVuZChyZXMuaGMsIGsgPSAzLCBrX2NvbG9ycyA9ICJqY28iLAogICAgICAgICAgdHlwZSA9ICJwaHlsb2dlbmljIiwgcmVwZWwgPSBUUlVFKQpnZ3JlcApgYGAKCmBgYHtyfQpmdml6X2RlbmQocmVzLmhjLCBrID0gMywgIyBDdXQgaW4gZm91ciBncm91cHMKICAgICAgICAgIGtfY29sb3JzID0gImpjbyIsCiAgICAgICAgICB0eXBlID0gInBoeWxvZ2VuaWMiLCAKICAgICAgICAgIHJlcGVsID0gVFJVRSwKICAgICAgICAgIHBoeWxvX2xheW91dCA9ICJsYXlvdXRfd2l0aF9kcmwiKQpgYGAKCgpgYGB7cn0KZnZpel9kZW5kKHJlcy5oYywgayA9IDMsICMgQ3V0IGluIGZvdXIgZ3JvdXBzCiAgICAgICAgICBrX2NvbG9ycyA9ICJqY28iLAogICAgICAgICAgdHlwZSA9ICJwaHlsb2dlbmljIiwgCiAgICAgICAgICByZXBlbCA9IFRSVUUsCiAgICAgICAgICBwaHlsb19sYXlvdXQgPSAibGF5b3V0X2FzX3RyZWUiKQpgYGAKCgpgYGB7cn0KZnZpel9kZW5kKHJlcy5oYywgayA9IDMsICMgQ3V0IGluIGZvdXIgZ3JvdXBzCiAgICAgICAgICBrX2NvbG9ycyA9ICJqY28iLAogICAgICAgICAgdHlwZSA9ICJwaHlsb2dlbmljIiwgCiAgICAgICAgICByZXBlbCA9IFRSVUUsCiAgICAgICAgICBwaHlsb19sYXlvdXQgPSAibGF5b3V0LmdlbSIpCmBgYAoKCmBgYHtyfQpmdml6X2RlbmQocmVzLmhjLCBrID0gMywgIyBDdXQgaW4gZm91ciBncm91cHMKICAgICAgICAgIGtfY29sb3JzID0gImpjbyIsCiAgICAgICAgICB0eXBlID0gInBoeWxvZ2VuaWMiLCAKICAgICAgICAgIHJlcGVsID0gVFJVRSwKICAgICAgICAgIHBoeWxvX2xheW91dCA9ICJsYXlvdXQubWRzIikKYGBgCgoKYGBge3J9CmdnMTAgPC0gZnZpel9kZW5kKHJlcy5oYywgayA9IDMsICMgQ3V0IGluIGZvdXIgZ3JvdXBzCiAgICAgICAgICBrX2NvbG9ycyA9ICJqY28iLAogICAgICAgICAgdHlwZSA9ICJwaHlsb2dlbmljIiwgCiAgICAgICAgICByZXBlbCA9IFRSVUUsCiAgICAgICAgICBwaHlsb19sYXlvdXQgPSAibGF5b3V0X3dpdGhfbGdsIikKZ2cxMApgYGAKCgojIyBDb21wYXJlIGNsdXN0ZXJpbmcgYWxnb3JpdGhtcyBpbiBSCgpgYGB7cn0KbGlicmFyeShjbFZhbGlkKQojIElyaXMgZGF0YSBzZXQ6CiMgLSBSZW1vdmUgU3BlY2llcyBjb2x1bW4gYW5kIHNjYWxlIGRmIDwtIHNjYWxlKGlyaXNbLCAtNV0pCiMgQ29tcHV0ZSBjbFZhbGlkCmNsbWV0aG9kcyA8LSBjKCJoaWVyYXJjaGljYWwiLCJrbWVhbnMiLCJwYW0iKSAKaW50ZXJuIDwtIGNsVmFsaWQoCiAgY2hlc19jbHVzdGVyICU+JSBhcy5tYXRyaXgsIAogIG5DbHVzdCA9IDI6OCwKICBjbE1ldGhvZHMgPSBjbG1ldGhvZHMsIAogIHZhbGlkYXRpb24gPSAiaW50ZXJuYWwiCikgCnN1bW1hcnkoaW50ZXJuKQpgYGAKCmBgYHtyLCBldmFsID0gRn0KIyBTdGFiaWxpdHkgbWVhc3VyZXMKY2xtZXRob2RzIDwtIGMoImhpZXJhcmNoaWNhbCIsImttZWFucyIsInBhbSIpCnN0YWIgPC0gY2xWYWxpZCgKICBjaGVzX2NsdXN0ZXIgJT4lIGFzLm1hdHJpeCwKICBuQ2x1c3QgPSAyOjYsIAogIGNsTWV0aG9kcyA9IGNsbWV0aG9kcywKICB2YWxpZGF0aW9uID0gInN0YWJpbGl0eSIKKSAjIERpc3BsYXkgb25seSBvcHRpbWFsIFNjb3JlcwpvcHRpbWFsU2NvcmVzKHN0YWIpCmBgYAoKCiMjIE1vZGVsLUJhc2VkIENsdXN0ZXJpbmcKClRoZSBtb2RlbCBwYXJhbWV0ZXJzIGNhbiBiZSBlc3RpbWF0ZWQgdXNpbmcgdGhlIEV4cGVjdGF0aW9uLU1heGltaXphdGlvbiAoRU0pIGFsZ29yaXRobSBpbml0aWFsaXplZCBieSBoaWVyYXJjaGljYWwgbW9kZWwtYmFzZWQgY2x1c3RlcmluZy4gRWFjaCBjbHVzdGVyIGsgaXMgY2VudGVyZWQgYXQgdGhlIG1lYW5zIM68aywgd2l0aCBpbmNyZWFzZWQgZGVuc2l0eSBmb3IgcG9pbnRzIG5lYXIgdGhlIG1lYW4uCgoKYGBge3J9CmxpYnJhcnkobWNsdXN0KQptYyA8LSBNY2x1c3QoY2hlc19jbHVzdGVyKSAjIE1vZGVsLWJhc2VkLWNsdXN0ZXJpbmcgCnN1bW1hcnkobWMpCmBgYAoKCmBgYHtyfQojIEJJQyB2YWx1ZXMgdXNlZCBmb3IgY2hvb3NpbmcgdGhlIG51bWJlciBvZiBjbHVzdGVycyAKZnZpel9tY2x1c3QobWMsICJCSUMiLCBwYWxldHRlID0gImpjbyIpCiMgQ2xhc3NpZmljYXRpb246IHBsb3Qgc2hvd2luZyB0aGUgY2x1c3RlcmluZyAKZnZpel9tY2x1c3QobWMsICJjbGFzc2lmaWNhdGlvbiIsIGdlb20gPSAicG9pbnQiLApwb2ludHNpemUgPSAxLjUsIHBhbGV0dGUgPSAiamNvIikgIyBDbGFzc2lmaWNhdGlvbiB1bmNlcnRhaW50eQpmdml6X21jbHVzdChtYywgInVuY2VydGFpbnR5IiwgcGFsZXR0ZSA9ICJqY28iKQpgYGAKCgpgYGB7cn0KY2hlcyAlPiUgCiAgZ2dwbG90KGFlcyhsaWJlcmFsaXNtLCBwb3B1bGlzbSwgY29sb3VyID0gbWMkY2xhc3NpZmljYXRpb24pKSArIAogIGdlb21fcG9pbnQoKSArCiAgI2dlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIGZvcm11bGEgPSB5IH4gcG9seSh4LCAyKSkrCiAgI2dlb21fdGV4dF9yZXBlbChhZXMobGliZXJhbGlzbSwgcG9wdWxpc20sIGxhYmVsID0gcGFydHlfY250cnkpKSArCiAgZ2d0aGVtZXM6OnRoZW1lX2hjKCkgKwogIHZpcmlkaXM6OnNjYWxlX2NvbG9yX3ZpcmlkaXMoKSArIAogIGdlb21fZGVuc2l0eTJkKGFscGhhID0gLjcsIGNvbG9yID0gImdyYXkiKSAjIEFkZCAyRCBkZW5zaXR5IApgYGAKCgoKYGBge3IsIGV2YWwgPSBGfQpsaWJyYXJ5KGhpZ2hjaGFydGVyKQoKZGYxIDwtIHRpYmJsZSh2b3RlID0gcGFzdGUoY2hlc19jbHVzdGVyX2RhdGEkcGFydHlfbmFtZSwgY2hlc19jbHVzdGVyX2RhdGEkdm90ZV9pZCwgc2VwID0gIiAiKSwgY2x1c3RlciA9IGszJGNsdXN0ZXIsIHggPSBhcy52ZWN0b3IoY2hlc19jbHVzdGVyJGxpYmVyYWxpc20pLCB5ID0gYXMudmVjdG9yKGNoZXNfY2x1c3RlciRwb3B1bGlzbTIpKSAlPiUKICBmaWx0ZXIoc3RyaW5ncjo6c3RyX2RldGVjdCh2b3RlLCAiREVfIikpCmhjaGFydChkZjEsIGhjYWVzKHggPSB4LCB5ID0geSwgbmFtZSA9IHZvdGUsIGNvbG9yID0gY2x1c3RlciksIHR5cGUgPSAnc2NhdHRlcicpICU+JQogIGhjX2FkZF90aGVtZShoY190aGVtZV9zbXBsKCkpICU+JQogIGhjX3Rvb2x0aXAoCiAgICBmb3JtYXR0ZXIgPSBKUygiZnVuY3Rpb24oKXsKICAgICAgICAgICAgICAgICAgICByZXR1cm4gKCdQYXJ0eTogPHN0cm9uZz4nICsgdGhpcy5wb2ludC52b3RlICsgJzwvc3Ryb25nPjxicj4gWDogJyArIHRoaXMueCArICcgPGJyPiBZOiAnICsgdGhpcy55ICsgJyA8YnI+JykKICAgICAgICAgICAgICAgICAgfSIpKSAlPiUKICBoY19jaGFydCh6b29tVHlwZSA9ICJ4eSIpCmBgYAoKIyMgV29ybGQgTWFwCgpgYGB7cn0KbGlicmFyeShnZ3Bsb3QyKQp3b3JsZCA8LSBtYXBfZGF0YSgid29ybGQiKQp3b3JsZCRpc28zIDwtIGNvdW50cnljb2RlOjpjb3VudHJ5Y29kZSh3b3JsZCRyZWdpb24sICJjb3VudHJ5Lm5hbWUiLCAiaXNvM2MiKQoKY2hlcyA8LSBjaGVzICU+JQogIG11dGF0ZShjb3VudHJ5ID0gc3RyaW5ncjo6c3RyX3JlcGxhY2Uodm90ZV9pZCwgIl8uKj8kIiwgIiIpKSAlPiUKICBtdXRhdGUoaXNvMyA9IGNvdW50cnljb2RlOjpjb3VudHJ5Y29kZShjb3VudHJ5LCAiaXNvMmMiLCAiaXNvM2MiKSkKd29ybGQkdmFsdWUgPC0gaWZlbHNlKHdvcmxkJGlzbzMgJWluJSB1bmlxdWUoY2hlcyRpc28zKSwgInllcyIsICJubyIpCiMgdGFibGUod29ybGQkdmFsdWUpCiMgd29ybGQgJT4lIAojICAgZ2dwbG90KGFlcyhsb25nLCBsYXQsIGdyb3VwID0gZ3JvdXApKSArIAojICAgICBnZW9tX3BvbHlnb24oZmlsbD0nZ3JleScpCgpnZ21hcCA8LSB3b3JsZCAlPiUgCiAgZ2dwbG90KGFlcyhsb25nLCBsYXQsIGdyb3VwID0gZ3JvdXAsIGZpbGwgPSB2YWx1ZSkpICsgCiAgZ2VvbV9wb2x5Z29uKCkgKwogICN4bGltKC0yMCw1MCkgKyAKICAjeWxpbSgzMCw4MCkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKCJzZWxlY3RlZCIsIHZhbHVlcyA9IGMoImdyYXk5MCIsICJibHVlIikpICsKICB0aGVtZV9tYXAoKQpnZ21hcApgYGAKCgoKYGBge3IsIGV2YWwgPSBGfQojZXNzX2NsZWFuIDwtIGVzc19zdWIgICU+JSAKICAjIG11dGF0ZShldV9tZW1iZXIgPQogICMgICAgICAgICAgcmVjb2RlX2ZhY3RvcihjbnRyeSwKICAjICAgICAgICAgICAgICAgREUgPSAxOTU4LCBCRSA9IDE5NTgsIEZSID0gMTk1OCwgTkwgPSAxOTU4LCBJRSA9IDE5NzMsCiAgIyAgICAgICAgICAgICAgIEdCID0gMTk3MywgRkkgPSAxOTk1LCBBVCA9IDE5OTUsIFNFID0gMTk5NSwgRUUgPSAyMDA0LAogICMgICAgICAgICAgICAgICBQTCA9IDIwMDQsIFNJID0gMjAwNCwgQ1ogPSAyMDA0LCBDSCA9IDAsIElMID0gMCwKICAjICAgICAgICAgICAgICAgSVMgPSAwLCBOTyA9IDAsIFJVID0gMAogICMgICAgICAgICAgICAgKQogICMgICAgICAgKSAlPiUKICAjIG11dGF0ZShwb3N0X2NvbSA9IGlmZWxzZShyZWdpb24gJWluJSBjKCJFc3RvbmlhIiwgIlBvbGFuZCIsICJTbG92ZW5pYSIsICJDemVjaCBSZXB1YmxpYyIsICJSdXNzaWFuIEZlZGVyYXRpb24iKSwgIlBvc3QgQyIsICJXZXN0IikpCmBgYAoKCgojIyBHZXQgSW5mbwoKKiBob3JzZSBzaG9lIHRoZW9yeQoqIFNldCB1cCBSbWFya2Rvd24gcGFwZXIgdGVtcGxhdGUKKiBTZXQgdXAgUHJvamVjdCBwYWdlCgoKYGBge3IsIGV2YWwgPSBGfQpwNSA8LSBzdGVwNSAlPiUKICBzZWxlY3QoZ25kciwgZWR1LCBpbmNvbWUsIHJlbCwgeWVhcikgJT4lCiAgZ2F0aGVyKCJ2YXIiLCAidmFsdWUiKSAlPiUKICBnZ3Bsb3QoYWVzKHZhbHVlLCBmaWxsID0gdmFyKSkgKwogIGdlb21fYmFyKCkgKwogIGZhY2V0X3dyYXAofnZhciwgc2NhbGVzID0gImZyZWUiKSArCiAgdmlyaWRpczo6c2NhbGVfZmlsbF92aXJpZGlzKGRpc2NyZXRlID0gVCkKcDUKYGBgCgoKCgoK